{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1> Time series prediction using RNNs, with TensorFlow and Cloud ML Engine </h1>\n",
    "\n",
    "This notebook illustrates:\n",
    "<ol>\n",
    "<li> Creating a Recurrent Neural Network in TensorFlow\n",
    "<li> Creating a Custom Estimator in tf.contrib.learn \n",
    "<li> Training on Cloud ML Engine\n",
    "</ol>\n",
    "\n",
    "<p>\n",
    "\n",
    "<h3> Simulate some time-series data </h3>\n",
    "\n",
    "Essentially a set of sinusoids with random amplitudes and frequencies."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!pip install --upgrade tensorflow"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.7.0\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "print tf.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f022d43c510>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import seaborn as sns\n",
    "import pandas as pd\n",
    "\n",
    "SEQ_LEN = 10\n",
    "def create_time_series():\n",
    "  freq = (np.random.random()*0.5) + 0.1  # 0.1 to 0.6\n",
    "  ampl = np.random.random() + 0.5  # 0.5 to 1.5\n",
    "  x = np.sin(np.arange(0,SEQ_LEN) * freq) * ampl\n",
    "  return x\n",
    "\n",
    "for i in xrange(0, 5):\n",
    "  sns.tsplot( create_time_series() );  # 5 series"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def to_csv(filename, N):\n",
    "  with open(filename, 'w') as ofp:\n",
    "    for lineno in xrange(0, N):\n",
    "      seq = create_time_series()\n",
    "      line = \",\".join(map(str, seq))\n",
    "      ofp.write(line + '\\n')\n",
    "\n",
    "to_csv('train.csv', 1000)  # 1000 sequences\n",
    "to_csv('valid.csv',  50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!head -5 train.csv valid.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2> RNN </h2>\n",
    "\n",
    "For more info, see:\n",
    "<ol>\n",
    "<li> http://colah.github.io/posts/2015-08-Understanding-LSTMs/ for the theory\n",
    "<li> https://www.tensorflow.org/tutorials/recurrent for explanations\n",
    "<li> https://github.com/tensorflow/models/tree/master/tutorials/rnn/ptb for sample code\n",
    "</ol>\n",
    "\n",
    "Here, we are trying to predict from 8 values of a timeseries, the next two values.\n",
    "\n",
    "<p>\n",
    "\n",
    "<h3> Imports </h3>\n",
    "\n",
    "Several tensorflow packages and shutil"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import shutil\n",
    "from tensorflow.contrib.learn import ModeKeys\n",
    "import tensorflow.contrib.rnn as rnn"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3> Input Fn to read CSV </h3>\n",
    "\n",
    "Our CSV file structure is quite simple -- a bunch of floating point numbers (note the type of DEFAULTS). We ask for the data to be read BATCH_SIZE sequences at a time.  The Estimator API in tf.contrib.learn wants the features returned as a dict. We'll just call this timeseries column 'rawdata'.\n",
    "<p>\n",
    "Our CSV file sequences consist of 10 numbers. We'll assume that 8 of them are inputs and we need to predict the next two."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "DEFAULTS = [[0.0] for x in xrange(0, SEQ_LEN)]\n",
    "BATCH_SIZE = 20\n",
    "TIMESERIES_COL = 'rawdata'\n",
    "N_OUTPUTS = 2  # in each sequence, 1-8 are features, and 9-10 is label\n",
    "N_INPUTS = SEQ_LEN - N_OUTPUTS"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Reading data using the Estimator API in tf.learn requires an input_fn. This input_fn needs to return a dict of features and the corresponding labels.\n",
    "<p>\n",
    "So, we read the CSV file.  The Tensor format here will be batchsize x 1 -- entire line.  We then decode the CSV. At this point, all_data will contain a list of Tensors. Each tensor has a shape batchsize x 1.  There will be 10 of these tensors, since SEQ_LEN is 10.\n",
    "<p>\n",
    "We split these 10 into 8 and 2 (N_OUTPUTS is 2).  Put the 8 into a dict, call it features.  The other 2 are the ground truth, so labels."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# read data and convert to needed format\n",
    "def read_dataset(filename, mode=ModeKeys.TRAIN):\n",
    "  def _input_fn():\n",
    "    num_epochs = 100 if mode == ModeKeys.TRAIN else 1\n",
    "    \n",
    "    # could be a path to one file or a file pattern.\n",
    "    input_file_names = tf.train.match_filenames_once(filename)\n",
    "    \n",
    "\n",
    "    filename_queue = tf.train.string_input_producer(\n",
    "        input_file_names, num_epochs=num_epochs, shuffle=True)\n",
    "    reader = tf.TextLineReader()\n",
    "    _, value = reader.read_up_to(filename_queue, num_records=BATCH_SIZE)\n",
    "\n",
    "    value_column = tf.expand_dims(value, -1, name='value')\n",
    "    print('readcsv={}'.format(value_column))\n",
    "    \n",
    "    # all_data is a list of tensors\n",
    "    all_data = tf.decode_csv(value_column, record_defaults=DEFAULTS)  \n",
    "    inputs = all_data[:len(all_data)-N_OUTPUTS]  # first few values\n",
    "    label = all_data[len(all_data)-N_OUTPUTS : ] # last few values\n",
    "    \n",
    "    # from list of tensors to tensor with one more dimension\n",
    "    inputs = tf.concat(inputs, axis=1)\n",
    "    label = tf.concat(label, axis=1)\n",
    "    print('inputs={}'.format(inputs))\n",
    "\n",
    "    return {TIMESERIES_COL: inputs}, label   # dict of features, label\n",
    "\n",
    "  return _input_fn"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3> Define RNN </h3>\n",
    "\n",
    "A recursive neural network consists of possibly stacked LSTM cells.\n",
    "<p>\n",
    "The RNN has one output per input, so it will have 8 output cells.  We use only the last output cell, but rather use it directly, we do a matrix multiplication of that cell by a set of weights to get the actual predictions. This allows for a degree of scaling between inputs and predictions if necessary (we don't really need it in this problem).\n",
    "<p>\n",
    "Finally, to supply a model function to the Estimator API, you need to return a ModelFnOps. The rest of the function creates the necessary objects."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "LSTM_SIZE = 3  # number of hidden layers in each of the LSTM cells\n",
    "\n",
    "# create the inference model\n",
    "def simple_rnn(features, labels, mode, params):\n",
    "  # 0. Reformat input shape to become a sequence\n",
    "  x = tf.split(features[TIMESERIES_COL], N_INPUTS, 1)\n",
    "  #print 'x={}'.format(x)\n",
    "    \n",
    "  # 1. configure the RNN\n",
    "  lstm_cell = rnn.BasicLSTMCell(LSTM_SIZE, forget_bias=1.0)\n",
    "  outputs, _ = tf.nn.static_rnn(lstm_cell, x, dtype=tf.float32)\n",
    "\n",
    "  # slice to keep only the last cell of the RNN\n",
    "  outputs = outputs[-1]\n",
    "  #print 'last outputs={}'.format(outputs)\n",
    "  \n",
    "  # output is result of linear activation of last layer of RNN\n",
    "  weight = tf.Variable(tf.random_normal([LSTM_SIZE, N_OUTPUTS]))\n",
    "  bias = tf.Variable(tf.random_normal([N_OUTPUTS]))\n",
    "  predictions = tf.matmul(outputs, weight) + bias\n",
    "    \n",
    "  # 2. loss function, training/eval ops\n",
    "  if mode == ModeKeys.TRAIN or mode == ModeKeys.EVAL:\n",
    "     loss = tf.losses.mean_squared_error(labels, predictions)\n",
    "     train_op = tf.contrib.layers.optimize_loss(\n",
    "         loss=loss,\n",
    "         global_step=tf.train.get_global_step(),\n",
    "         learning_rate=0.01,\n",
    "         optimizer=\"SGD\")\n",
    "     eval_metric_ops = {\n",
    "      \"rmse\": tf.metrics.root_mean_squared_error(labels, predictions)\n",
    "     }\n",
    "  else:\n",
    "     loss = None\n",
    "     train_op = None\n",
    "     eval_metric_ops = None\n",
    "  \n",
    "  # 3. Create predictions\n",
    "  predictions_dict = {\"predicted\": predictions}\n",
    "\n",
    "  # 4. Create export outputs  \n",
    "  export_outputs = {\"predicted\": tf.estimator.export.PredictOutput(predictions)}\n",
    "\n",
    "  # 5. return ModelFnOps\n",
    "  return tf.estimator.EstimatorSpec(\n",
    "      mode=mode,\n",
    "      predictions=predictions_dict,\n",
    "      loss=loss,\n",
    "      train_op=train_op,\n",
    "      eval_metric_ops=eval_metric_ops,\n",
    "      export_outputs=export_outputs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3> Experiment </h3>\n",
    "\n",
    "Distributed training is launched off using an Experiment.  The key line here is that we use tflearn.Estimator rather than, say tflearn.DNNRegressor.  This allows us to provide a model_fn, which will be our RNN defined above.  Note also that we specify a serving_input_fn -- this is how we parse the input data provided to us at prediction time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def get_train():\n",
    "  return read_dataset('train.csv', mode=ModeKeys.TRAIN)\n",
    "\n",
    "def get_valid():\n",
    "  return read_dataset('valid.csv', mode=ModeKeys.EVAL)\n",
    "\n",
    "def serving_input_receiver_fn():\n",
    "  feature_placeholders = {\n",
    "    TIMESERIES_COL: tf.placeholder(tf.float32, [None, N_INPUTS])\n",
    "  }\n",
    "\n",
    "  features = {\n",
    "    key: tf.expand_dims(tensor, -1)\n",
    "    for key, tensor in feature_placeholders.items()\n",
    "  }\n",
    "\n",
    "  features[TIMESERIES_COL] = tf.squeeze(features[TIMESERIES_COL], axis=[2], name='timeseries')\n",
    "  \n",
    "  print('serving: features={}'.format(features[TIMESERIES_COL]))\n",
    "\n",
    "  return tf.estimator.export.ServingInputReceiver(features, feature_placeholders)\n",
    "\n",
    "\n",
    "def experiment_fn(output_dir):\n",
    "  train_spec = tf.estimator.TrainSpec(input_fn=get_train(), max_steps=1000)\n",
    "  exporter = tf.estimator.FinalExporter('timeseries',\n",
    "    serving_input_receiver_fn)\n",
    "  eval_spec = tf.estimator.EvalSpec(input_fn=get_valid(), \n",
    "    exporters=[exporter])\n",
    "\n",
    "  estimator = tf.estimator.Estimator(model_fn=simple_rnn, model_dir=output_dir)\n",
    "\n",
    "  tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)\n",
    "\n",
    "OUTPUT_DIR = 'outputdir'\n",
    "shutil.rmtree(OUTPUT_DIR, ignore_errors=True) # start fresh each time\n",
    "\n",
    "experiment_fn(OUTPUT_DIR)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3> Standalone Python module </h3>\n",
    "\n",
    "To train this on Cloud ML Engine, we take the code in this notebook, make an standalone Python module."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%bash\n",
    "# run module as-is\n",
    "REPO=$(pwd)\n",
    "echo $REPO\n",
    "rm -rf outputdir\n",
    "export PYTHONPATH=${PYTHONPATH}:${REPO}/simplernn\n",
    "python -m trainer.task \\\n",
    "   --train_data_paths=\"${REPO}/train.csv*\" \\\n",
    "   --eval_data_paths=\"${REPO}/valid.csv*\"  \\\n",
    "   --output_dir=${REPO}/outputdir \\\n",
    "   --job-dir=./tmp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Try out online prediction.  This is how the REST API will work after you train on Cloud ML Engine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%writefile test.json\n",
    "{\"rawdata\": [0.0,0.0527,0.10498,0.1561,0.2056,0.253,0.2978,0.3395]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "predictions:\n",
      "- predicted:\n",
      "  - 0.456365\n",
      "  - 0.48135\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: 2017-06-27 17:52:12.098509: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.\n",
      "2017-06-27 17:52:12.098577: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.\n",
      "2017-06-27 17:52:12.098596: W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations.\n",
      "WARNING:root:MetaGraph has multiple signatures 2. Support for multiple signatures is limited. By default we select named signatures.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "%bash\n",
    "MODEL_DIR=$(ls ./outputdir/export/Servo/)\n",
    "gcloud ml-engine local predict --model-dir=./outputdir/export/Servo/$MODEL_DIR --json-instances=test.json"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3> Cloud ML Engine </h3>\n",
    "\n",
    "Now to train on Cloud ML Engine."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%bash\n",
    "# run module on Cloud ML Engine\n",
    "REPO=$(pwd)\n",
    "BUCKET=cloud-training-demos-ml # CHANGE AS NEEDED\n",
    "OUTDIR=gs://${BUCKET}/simplernn/model_trained\n",
    "JOBNAME=simplernn_$(date -u +%y%m%d_%H%M%S)\n",
    "REGION=us-central1\n",
    "gcloud storage rm --recursive --continue-on-error $OUTDIR\n",    "gcloud ml-engine jobs submit training $JOBNAME \\\n",
    "   --region=$REGION \\\n",
    "   --module-name=trainer.task \\\n",
    "   --package-path=${REPO}/simplernn/trainer \\\n",
    "   --job-dir=$OUTDIR \\\n",
    "   --staging-bucket=gs://$BUCKET \\\n",
    "   --scale-tier=BASIC \\\n",
    "   --runtime-version=1.2 \\\n",
    "   -- \\\n",
    "   --train_data_paths=\"gs://${BUCKET}/train.csv*\" \\\n",
    "   --eval_data_paths=\"gs://${BUCKET}/valid.csv*\"  \\\n",
    "   --output_dir=$OUTDIR \\\n",
    "   --num_epochs=100"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2> Variant: long sequence </h2>\n",
    "\n",
    "To create short sequences from a very long sequence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input= [  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.]\n",
      "output= [[ 1.  2.  3.  4.  5.]\n",
      " [ 2.  3.  4.  5.  6.]\n",
      " [ 3.  4.  5.  6.  7.]\n",
      " [ 4.  5.  6.  7.  8.]\n",
      " [ 5.  6.  7.  8.  9.]]\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "\n",
    "def breakup(sess, x, lookback_len):\n",
    "  N = sess.run(tf.size(x))\n",
    "  windows = [tf.slice(x, [b], [lookback_len]) for b in xrange(0, N-lookback_len)]\n",
    "  windows = tf.stack(windows)\n",
    "  return windows\n",
    "\n",
    "x = tf.constant(np.arange(1,11, dtype=np.float32))\n",
    "with tf.Session() as sess:\n",
    "    print 'input=', x.eval()\n",
    "    seqx = breakup(sess, x, 5)\n",
    "    print 'output=', seqx.eval()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Copyright 2017 Google Inc. Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
